#include "type.h"
#include "mem/dram.h"
//#include <stdio.h>
#include <string.h>


Dram::Dram(unsigned int page_size, u8 default_value){
    CHECK(page_size!=0);
    int tmp = -1;
    unsigned int ps = page_size;
    while(ps){
        ps=ps>>1;
        tmp++;
    }
    PageSizeBit = tmp;
    PageSize = 1 << PageSizeBit;
    DefaultValue = default_value;
}

Dram::DramMapType::iterator Dram::find_page(u64 page_key){
    auto it = DramMap.find(page_key);
    if(it == DramMap.end()){
        DramMap.insert(
            std::make_pair(page_key,std::unique_ptr<Page>(new Page(PageSize))));
        it = DramMap.find(page_key);
    }
    return it;
}

void Dram::write_mem(u64 dst, void* src, u64 length){
    u64 page_key = dst >> PageSizeBit;
    auto it = find_page(page_key);
    u64 page_start = dst & (PageSize - 1);
    u64 page_remain = PageSize - page_start;
    if(length <= page_remain){
        memcpy((void*)(it->second->Memory_page + page_start), src, length);
        return;
    }
    else{
        memcpy((void*)(it->second->Memory_page + page_start), src, page_remain);
        u8* src_tmp = (u8*)src + page_remain;
        u64 length_tmp = length - page_remain;
        page_key++;
        while(length_tmp > PageSize){
            it = find_page(page_key);
            memcpy((void*)it->second->Memory_page, src_tmp, PageSize);
            length_tmp -= PageSize;
            src_tmp += PageSize;
            page_key++;
        }
        it = find_page(page_key);
        memcpy((void*)it->second->Memory_page, src_tmp, length_tmp);
        return;
    }
}

void Dram::read_mem(void* dst, u64 src, u64 length){
    u64 page_key = src >> PageSizeBit;
    auto it = DramMap.find(page_key);
    u64 page_start = src & (PageSize - 1);
    u64 page_remain = PageSize - page_start;
    if(length <= page_remain){
        if(it != DramMap.end()){
            memcpy(dst, (void*)(it->second->Memory_page + page_start) , length);
        }
        else{
            memset(dst, DefaultValue, length);
        }
        return;
    }
    else{
        if(it != DramMap.end()){
            memcpy(dst, (void*)(it->second->Memory_page + page_start), page_remain);
        }
        else{
            memset(dst, DefaultValue, page_remain);
        }
        u8* dst_tmp = (u8*)dst + page_remain;
        u64 length_tmp = length - page_remain;
        page_key++;
        while(length_tmp > PageSize){
            it = DramMap.find(page_key);
            if(it != DramMap.end()){
                memcpy(dst_tmp, (void*)it->second->Memory_page, PageSize);
            }
            else{
                memset(dst_tmp, DefaultValue, PageSize);
            }
            length_tmp -= PageSize;
            dst_tmp += PageSize;
            page_key++;
        }
        it = DramMap.find(page_key);
        if(it != DramMap.end()){
            memcpy(dst_tmp, (void*)it->second->Memory_page, length_tmp);
        }
        else{
            memset(dst_tmp, DefaultValue, length_tmp);
        }
        return;
    }
}
